#!/usr/bin/python
# coding=UTF8

#import _mysql
import MySQLdb as mdb
import os.path
import datetime
import logging
import logging.handlers


from optparse import OptionParser
from TimePeriod import inPeriod
from time import sleep,ctime,time
from os import fork, chdir, setsid, umask
from sys import exit 
from pycall.callfile import *
from pycall.callfileexceptions import *

# class DB:
# 	conn = None
# 	def connect(self):
# 		try:
# 			self.conn = MySQLdb.connect('localhost','root','','autodial')
# 		except (AttributeError, MySQLdb.OperationalError), e:
# 			logger.error("Error %d: %s" % (e.args[0], e.args[1]))
# 			exit(1)
# 	def cursor(self):
# 		try:
# 			return self.conn.cursor()
# 		except (AttributeError, MySQLdb.OperationalError), e:
# 			logger.error("Error %d: %s" % (e.args[0], e.args[1]))
# 			self.connect()
# 			return self.conn.cursor()

def main():
	global verbose
	global db
	global logger
	global cursor
	# Номер первой линии
	lineid = 1
	# Кол-во секунд между проверками dialstatus и на пустой результат
	sec = 5
	# Количество секунд между генерацией звонков
	calldelay = 30
	
	dial_status_logged = 0
	empty_result_logged = 0
	try:
		db = mdb.connect()
		db = mdb.connect('127.0.0.1','callgen','callgen','autodial')
		logger.info("Connected to Mysql")
	except mdb.Error, e:
		logger.error("Error %d: %s" % (e.args[0], e.args[1]))
		exit (1)
	cursor = db.cursor()
	while 1:
		try:
			# Проверяем что в базе выставлен dialstatus в 1 иначе просто спим
			if  check_dial_status() == 0: 
				# Проверяем что строку в логе еще не писали
				if dial_status_logged == 0:
					logger.debug('Stoped, dialstatus field is 0')
				# Выставляем флаг, чтобы не повторять запись в лог
				dial_status_logged = 1
				sleep(sec)
			else:
				logging.debug('Start')
				dial_status_logged=0
				cursor.execute('SELECT n.id,n.number,n.groupid,n.balance,n.tried,g.period FROM numbers n JOIN groups g ON (g.id=n.groupid) WHERE tried=0 LIMIT 100;')
				rows=cursor.fetchall()
				# Если строки есть
				if rows:
					todo = True
					logger.debug('Result not null')
					empty_result_logged = 0
					# то берем каждую и присваиваем переменным соответсвующие значения полей
					for row in rows:
						# пишем в переменные результат запроса
						(nid, num, group, balance, tried, period) = row[:6]		
						# Проверка даты
						now	= datetime.now()
						try:
							periodchk = inPeriod (period, now)
							logger.debug ("Is group in period - %s" % periodchk)
						except Exception, e:
							logger.error( "%s - %s" % (e, period))
							periodchk = False
						if periodchk:
							# Делаем звонок
							createcall(nid,num,group,balance,lineid)
							# и увеличиваем счетчик на 1
							lineid = lineid + 1
						else:
							#if verbose: print "%s, %s: timeperiod %s" % (nid,now, period)
							todo = False
							
						# Количество одновременных звонков - 5
						if lineid > 5:
							logger.debug("5 calls generated, sleep %s sec..." % sec)
							sleep(calldelay)
							lineid = 1
							todo = True
					# Закончили запрос спим
					if not todo: 
						logger.debug("Nothing to do, sleep %s sec..." % sec)
					sleep (sec)
				# Если запрос ничего не выдал, то спим
				else:
					# Проверяем что строку в логе еще не писали
					if empty_result_logged == 0:
						logger.debug("Empty result, nothing to do, sleep %s sec..." % sec)
					# Выставляем флаг, чтобы не повторять запись
					empty_result_logged = 1
					sleep(sec)
					
		except (KeyboardInterrupt):
			logger.info("CTRL-C... exit")
			exit(0)
		except (SystemExit):
			logger.info("Exit")
			exit(0)

def createcall(nid,num,group,balance,lineid):
	
	callfile = CallFile(
		trunk_type = 'Local',
		trunk_name = 'gencall/n',
		number = num,
		callerid_num = '1111',
		context = 'gencall',
		extension = 's',
		priority = '1',
		wait_time = '600',
		archive = 'True',
		always_delete = 'True',
		user = 'asterisk', # chown the callfile to user 'asterisk'.
		sets = {
			'nid'		: nid,
			'num'		: num,
			'group' 	: group,
			'balance'	: balance,
			'lineid'	: lineid
		}
	)
	# Place the call now.
	try:
		# Создаем call-файл
		callfile.run()
		pass
	except NoActionDefined:
		logger.error("NoActionDefined exception")
	except NoUserException:
		logger.error("User %s doesn't exist. Skipping call." % callfile.user)
	except NoPermissionException:
		logger.error("We do not have the permissions to change ownership of the callfile to user %s. SKipping the call." % callfile.user)
	except Exception, e:
		logger.error(e)	
	else: 
		# Пишем в logfile
		logger.debug('%d call to %s group %s balance %s ID=%s' % (lineid, num, group, balance, nid))
		# Выставляем в таблице numbers флаги обработки звонков
		try:
			cursor.execute('UPDATE numbers set tried=1 where id=%s', nid)
		except mdb.OperationalError, e:
			logger.error("Error %d: %s" % (e.args[0], e.args[1]))

def check_dial_status():
	try:
		cursor.execute('SELECT * FROM control WHERE id=100')
	except mdb.Error, e:
		logger.error("Error %d: %s" % (e.args[0], e.args[1]))
		if e.args[0] == 2006:
			exit(1)
	r=cursor.fetchone()
	try:
		status = int(r[1])
	except:
		status = 0
		logger.error("INT function exception, check 'control' table please")
	return status

def process_num(process):
	# Возвращаем количество процессов
	return os.popen('pidof -x %s|wc -w' % process).read().rstrip()

	
if __name__ == '__main__':
	parser = OptionParser()
	parser.add_option("-d", "--daemon", dest="daemon",action="store_true",
				help="Demonize process")
	parser.add_option("-v", "--verbose", dest="verbose",action="store_true",
				help="Set verbose")			
	(options, args) = parser.parse_args()

	# ===== LOGGING ============================
	LOGFILE='/var/log/callgen/callgen.log'
	FORMAT='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
	logging.basicConfig(filename=LOGFILE,
						level=logging.NOTSET,
						datefmt='%y-%m-%d %H:%M:%S',
						format=FORMAT)
	logger = logging.getLogger('AutoDial')
	#rotatesize = logging.handlers.RotatingFileHandler(LOGFILE, 'a', 1048576, 100)
	rotatetime = logging.handlers.TimedRotatingFileHandler(LOGFILE, "midnight", 1, 100)
	console = logging.StreamHandler()
	formatter = logging.Formatter('%(asctime)s: %(message)s','%y-%m-%d %H:%M:%S')
	console.setFormatter(formatter)
	logging.getLogger('').addHandler(console)
	#logging.getLogger('').addHandler(rotatesize)
	#logging.getLogger('').addHandler(rotatetime)

#	console.setLevel(logging.DEBUG)
	
	#print logger.getEffectiveLevel()
	# Включаем дебаг
	if options.verbose:
		logger.setLevel(logging.DEBUG)
	if options.daemon:
		logging.getLogger('').removeHandler(console)
	else:
		print "console mode"
	
	if options.daemon:
		process = 'callgen'
		# Если количество процессов больше 1 (минус собственный) тогда выходим
		procnum = int(process_num(process))-1
		if procnum > 0:
			logger.error("Process already exist (%s)" % procnum)
			print "Process already exist (%s)" % procnum
			exit(0)
		try: 
			pid = fork() 
			if pid > 0:
				# exit first parent
				exit(0)
		except OSError, e:
			logger.error("fork #1 failed: %d (%s)" % (e.errno, e.strerror))
			exit(1)
	
		# decouple from parent environment
		chdir("/")
		setsid()
		umask(0)
		try:
			pid = fork()
			if pid > 0:
				# exit from second parent, print eventual PID before
				logger.info("Daemon PID %d" % pid)
				exit(0)
		except OSError, e:
			logger.error("fork #2 failed: %d (%s)" % (e.errno, e.strerror))
			exit(1)

	main()